/*
    Speedbump aka Project Kimbula
    Copyright (C) 2010  Ping Shin Ching

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses.

	Ping Shin Ching
	righteous.ninja@gmail.com OR ping_sc@hotmail.com
	More information at http://www.tidytutorials.com/p/speedbump.html
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rules.h"
#include "application.h"


/*************************************************************************
 * Initialize the filter manager
 *************************************************************************/
FilterChain::FilterChain(short log){
	filterChainCounter=0;
	filterLogging = log;
	filterChain = (Filter*)malloc(sizeof(Filter)*MAX_FILTER_LINKS);
}

FilterChain::~FilterChain(){
	//This has all been freed with the call to FilterFree
}

/*************************************************************************
 * Add a filter to the manager
 *************************************************************************/
int FilterChain::AddFilters(FilterInterface* fi, InitInterface *initp){
	if( filterChainCounter < MAX_FILTER_LINKS){
		if(fi->InitFilter(initp)==-1){
			loge<<"Filter "<< fi->GetFilterName() << 
			" didn't initialize correctly and was not added to the chain"<<lend;
			return -1;
		}
		filterChain[filterChainCounter].pfi = fi;
		strncpy(filterChain[filterChainCounter].filtername, fi->GetFilterName() , MAX_FILTER_NAME);
		filterChain[filterChainCounter].type = fi->GetFilterType();
		if(fi->GetFilterRedirect()){
			filterChain[filterChainCounter].filterredirect = (char*)malloc(sizeof(char)*FILTER_REDIRECTURL_SIZE);
			strncpy(filterChain[filterChainCounter].filterredirect, fi->GetFilterRedirect(), FILTER_REDIRECTURL_SIZE);
		}
		else
			filterChain[filterChainCounter].filterredirect=0;

		return ++filterChainCounter;
	}
	else{
		return -1;
	}
}


/*************************************************************************
 * Call the filter depending on the point
 *************************************************************************/
int FilterChain::PassFilters(FILTER_TYPE type, const char* ip, void* param1){
	int i;
	masterfilterredirect=0;

	for(i=0;i<filterChainCounter;i++){
		if((filterChain[i].type | type )== filterChain[i].type ){
			if(filterChain[i].pfi->DoFilter(ip,  type, (FilterData*)param1)==0){
				masterfilterredirect=filterChain[i].filterredirect;
				return 0;
			}
		}
	}
	return 1;
}


/*************************************************************************
 * Get the final redirect now used for final message
 *************************************************************************/
char* FilterChain::GetFinalFilterRedirect(){
	if(masterfilterredirect){
		return masterfilterredirect;
	}
	else{
		return 0;
	}
}


/*************************************************************************
 * Destroy the filter data
 *************************************************************************/
void FilterChain::FilterFree(){
	int i;
	PassFilters(FILTER_FREE, 0, 0);
	for(i=0;i<filterChainCounter;i++){
		if(filterChain[i].filterredirect){
			free(filterChain[i].filterredirect);
		}
		delete filterChain[i].pfi;
	}
	free(filterChain);
}


/*************************************************************************
 * Log the filter data
 *************************************************************************/
std::ofstream* FilterChain::GetFilterLogger(LOGLEVEL loglevel  ){
	
	if(filterLogging || loglevel<=LOG_ERROR)
		return (std::ofstream*)&(*proxylog.Getlogger(loglevel)<<"Filter: ");
	else
		return proxylog.GetNullLogger();
}

void FilterChain::FilterLogend(){
	if(filterLogging)
		proxylog.Logend();
}

/*************************************************************************
 * Static filter logging flag
 *************************************************************************/
short FilterChain::filterLogging=0;


/*************************************************************************
 * Static get message utility
 *************************************************************************/
FILTER_TYPE FilterChain::GetMessageType(char* msg){
	int msgtype;
	sscanf(msg, "{msg=%d}", &msgtype);
	return (FILTER_TYPE)msgtype;
}


/*************************************************************************
 * Static compare two unsigned char [] ips
 *************************************************************************/
int FilterChain::CompareTwoIPs(const char * ip1, const char* ip2){
	if(strcmp(ip1,ip2)==0)
		return 1;
	else
		return 0;
}


/*************************************************************************
 * Static assign one ip to another utility
 *************************************************************************/
void FilterChain::AssignIP(char* ip1, unsigned int ip1size, const char * ip2){
	strncpy(ip1, ip2, ip1size);
}

/*************************************************************************
 * Static Decode message utility
 *************************************************************************/
void FilterChain::DecodeMessage(const char* msg, unsigned int * msgtype, char* ip, unsigned int* up, unsigned int* down){
	sscanf(msg, "{msg=%d}{ip=%[^}]}{up=%u}{down=%u]}",  msgtype, ip, up, down);
	//printf("decoded msg %s:%s %u %u\n", msg, ip, *up, *down);
}
